﻿/**
 * @file audio_dev.h
 * Copyright (c) Gaaagaa. All rights reserved.
 * 
 * @author  : Gaaagaa
 * @date    : 2020-02-13
 * @version : 1.0.0.0
 * @brief   : 封装 SDL 相关 API 实现音频设备的 PCM 数据（采集、播放等）操作的工具类。
 */

#ifndef __AUDIO_DEV_H__
#define __AUDIO_DEV_H__

#include "xtypes.h"

////////////////////////////////////////////////////////////////////////////////

/**
 * @enum  xem_audio_format_t
 * @brief 相关的 PCM 音频采样格式枚举值（参照 SDL 中定义的宏常量而来）。
 */
typedef enum xem_audio_format_t
{
    X_AUDIO_U8     = 0x0008,         ///< Unsigned 8-bit samples
    X_AUDIO_S8     = 0x8008,         ///< Signed 8-bit samples
    X_AUDIO_U16LSB = 0x0010,         ///< Unsigned 16-bit samples
    X_AUDIO_S16LSB = 0x8010,         ///< Signed 16-bit samples
    X_AUDIO_U16MSB = 0x1010,         ///< As above, but big-endian byte order
    X_AUDIO_S16MSB = 0x9010,         ///< As above, but big-endian byte order
    X_AUDIO_U16    = X_AUDIO_U16LSB, ///< Defaults to LSB byte order.
    X_AUDIO_S16    = X_AUDIO_S16LSB, ///< Defaults to LSB byte order.

    X_AUDIO_S32LSB = 0x8020,         ///< 32-bit integer samples
    X_AUDIO_S32MSB = 0x9020,         ///< As above, but big-endian byte order
    X_AUDIO_S32    = X_AUDIO_S32LSB, ///< Defaults to LSB byte order.

    X_AUDIO_F32LSB = 0x8120,         ///< 32-bit floating point samples
    X_AUDIO_F32MSB = 0x9120,         ///< As above, but big-endian byte order
    X_AUDIO_F32    = X_AUDIO_F32LSB, ///< Defaults to LSB byte order.
} xem_audio_format_t;

////////////////////////////////////////////////////////////////////////////////
// audio_dev_t

/**
 * @class audio_dev_t
 * @brief 封装 SDL 相关 API 实现音频设备的 PCM 数据（采集、播放等）操作的工具类。
 * @note
 * audio_dev_t 只作为接口的抽象基类，在实际使用过程中，应使用其的派生类
 * adev_capture_t 或 adev_playout_t 进行实例化，实现数据的采集/播放操作。
 */
class audio_dev_t
{
    // common data types and interfaces
public:
    /**
     * @brief 音频数据回调接口。
     * 
     * @param [in ] xht_ctxt : 回调用户自定义的上下文标识句柄。
     * @param [in ] xmt_data : 音频操作所使用的缓存。
     * @param [in ] xit_size : 所使用缓存的大小。
     */
    typedef x_void_t (* xfun_cbk_t)(
                                x_handle_t xht_ctxt,
                                x_void_t * xmt_data,
                                x_int32_t  xit_size);

    /**
     * @struct audio_spec_t
     * @brief  音频设备的工作参数。
     */
    typedef struct audio_spec_t
    {
        x_uint8_t   xut_wmode    ;  ///< 工作模式（1，采集；0，播放）
        x_uint8_t   xut_channels ;  ///< 通道数
        x_uint16_t  xut_format   ;  ///< 音频格式（参看 xem_audio_format_t 枚举值）
        x_uint32_t  xut_frequency;  ///< 采样率
        xfun_cbk_t  xft_callback ;  ///< 音频数据操作（采集/播放）时的回调接口
        x_handle_t  xht_userctxt ;  ///< 回调用户自定义的上下文标识句柄
    } audio_spec_t;

    // common invoking
public:
    /**********************************************************/
    /**
     * @brief 以混合操作的方式，拷贝指定格式的音频数据。
     * 
     * @param [in ] xbt_dstbuf : 混合操作的目标音频数据缓存。
     * @param [in ] xbt_srcbuf : 混合操作的源音频数据缓存。
     * @param [in ] xut_format : 混合操作使用的音频格式（参看 xem_audio_format_t 枚举值）。
     * @param [in ] xut_length : 所操作的缓存有效数据长度。
     * @param [in ] xit_volume : 混合操作过程中，所限制的源音频音量值（取值范围 0 - 128）。
     * 
     */
    static x_void_t mix_copy(
                        x_byte_t * xbt_dstbuf,
                        x_byte_t * xbt_srcbuf,
                        x_uint16_t xut_format,
                        x_uint32_t xut_length,
                        x_int32_t  xit_volume = 128);

    // constructor/destructor
protected:
    /**
     * @param [in ] xut_wmode : 工作模式：0，播放模式；1，采集模式。
     */
    audio_dev_t(x_uint8_t xut_wmode);
    ~audio_dev_t(void);

    // public interfaces
public:
    /**********************************************************/
    /**
     * @brief 设置音频设备的数据操作时的回调接口。
     * @note  该接口必须在 open() 操作前调用，即处于非打开状态下调用。
     * 
     * @param [in ] xft_callback : 回调的函数接口。
     * @param [in ] xht_userctxt : 回调用户自定义的上下文标识句柄。
     * 
     * @return x_bool_t
     *         - 返回 X_TRUE ，设置成功；
     *         - 返回 X_FALSE，对象处于非打开状态，设置失败。
     */
    x_bool_t set_callback(xfun_cbk_t xft_callback, x_handle_t xht_userctxt);

    /**********************************************************/
    /**
     * @brief 是否为回调模式进行数据操作。
     */
    inline x_bool_t is_callback(void) const
    {
        return (X_NULL != m_audio_spec.xft_callback);
    }

    /**********************************************************/
    /**
     * @brief 打开音频设备。
     * 
     * @param [in ] xit_index     : 设备索引号（从 0 开始）；为 -1 时，取系统默认设备。
     * @param [in ] xut_channels  : 期望设备工作时的通道数。
     * @param [in ] xut_format    : 期望设备工作时的音频格式（参看 xem_audio_format_t 枚举值）。
     * @param [in ] xut_frequency : 期望设备工作时的采样率。
     * 
     * @return x_int32_t
     *         - 成功，返回 0 ；
     *         - 失败，返回 -1。
     */
    x_int32_t open(x_int32_t  xit_index,
                   x_uint8_t  xut_channels,
                   x_uint16_t xut_format,
                   x_uint32_t xut_frequency);

    /**********************************************************/
    /**
     * @brief 关闭音频设备。
     */
    x_void_t close(void);

    /**********************************************************/
    /**
     * @brief 判断当前音频设备是否已经处于打开的工作状态。
     */
    x_bool_t is_open(void);

    /**********************************************************/
    /**
     * @brief 当前音频设备的工作参数信息。
     */
    inline const audio_spec_t & audio_spec(void) const
    {
        return m_audio_spec;
    }

    /**********************************************************/
    /**
     * @brief 使当前打开的音频设备 暂停/恢复 工作。
     */
    x_void_t pause(x_bool_t xbt_pause);

    /**********************************************************/
    /**
     * @brief 返回当前音频设备中已缓存的数据大小。
     * @note  使用回调模式时，调用该接口无效。
     */
    x_uint32_t buffer_size(void);

    /**********************************************************/
    /**
     * @brief 清除音频设备已缓存的数据。
     * @note  使用回调模式时，调用该接口无效。
     */
    x_void_t clear_buffer(void);

    // data members
protected:
    x_handle_t   m_xht_device;  ///< 音频设备的操作句柄
    audio_spec_t m_audio_spec;  ///< 音频设备工作的相关参数信息
};

////////////////////////////////////////////////////////////////////////////////
// adev_capture_t

/**
 * @class adev_capture_t
 * @brief 音频（PCM 格式）数据采集操作的工具类。
 */
class adev_capture_t : public audio_dev_t
{
    // common interfaces
public:
    /**********************************************************/
    /**
     * @brief 获取音频采集设备的数量。
     */
    static x_int32_t dev_count(void);

    /**********************************************************/
    /**
     * @brief 获取音频采集设备的名称（UTF-8编码的字符串）。
     */
    static x_cstring_t dev_name(x_int32_t xit_index);

    // constructor/destructor
public:
    adev_capture_t(void);
    ~adev_capture_t(void);

    // public interfaces
public:
    /**********************************************************/
    /**
     * @brief 音频采集操作时，调用该接口采集实时的音频数据。
     * @note  在使用 非回调方式 采集音频数据时，调用该接口才有效。
     * 
     * @param [out] xmt_data : 接收采集到的音频数据缓存。
     * @param [in ] xut_size : 音频数据缓存的大小。
     * 
     * @return x_int32_t
     *         - 返回 >= 0，表示采集到的音频有效数据字节数；
     *         - 返回   -1，表示操作产生错误。
     */
    x_int32_t capture(x_byte_t * xmt_data, x_uint32_t xut_size);

    // data members
private:

};

////////////////////////////////////////////////////////////////////////////////
// adev_playout_t

/**
 * @class adev_playout_t
 * @brief 音频（PCM 格式）数据播放操作的工具类。
 */
class adev_playout_t : public audio_dev_t
{
    // common interfaces
public:
    /**********************************************************/
    /**
     * @brief 获取音频播放设备的数量。
     */
    static x_int32_t dev_count(void);

    /**********************************************************/
    /**
     * @brief 获取音频播放设备的名称（UTF-8编码的字符串）。
     */
    static x_cstring_t dev_name(x_int32_t xit_index);

    // constructor/destructor
public:
    adev_playout_t(void);
    ~adev_playout_t(void);

    // public interfaces
public:
    /**********************************************************/
    /**
     * @brief 音频播放操作时，调用该接口播放实时的音频数据。
     * @note  在使用 非回调方式 播放音频数据时，调用该接口才有效。
     * 
     * @param [in ] xmt_data : 待播放的音频数据缓存。
     * @param [in ] xut_size : 音频数据缓存的有效数据大小。
     * 
     * @return x_int32_t
     *         - 返回  0，表示操作成功；
     *         - 返回 -1，表示操作失败。
     */
    x_int32_t playout(x_byte_t * xmt_data, x_uint32_t xut_size);

    // data members
private:

};

////////////////////////////////////////////////////////////////////////////////

#endif // __AUDIO_DEV_H__
